package org.osiris.server.bussinesscore;

import java.util.Date;
import java.util.List;

import javax.persistence.Transient;

import org.apache.log4j.Logger;
import org.osiris.persistence.Detallerequisito;
import org.osiris.persistence.Incertidumbre;
import org.osiris.persistence.Requisito;
import org.osiris.persistence.Requisitosdeproyecto;
import org.osiris.persistence.RequisitosdeproyectoPK;
import org.osiris.persistence.Riesgo;
import org.osiris.persistence.Usuario;
import org.osiris.persistence.controllers.ComplejidadInterface;
import org.osiris.persistence.controllers.DetalleInterface;
import org.osiris.persistence.controllers.EstadoInterface;
import org.osiris.persistence.controllers.IncertidumbreInterface;
import org.osiris.persistence.controllers.PrioridadInterface;
import org.osiris.persistence.controllers.ProyectoInterface;
import org.osiris.persistence.controllers.RequisitoDeProyectoInterface;
import org.osiris.persistence.controllers.RequisitoInterface;
import org.osiris.persistence.controllers.SucategoriaInterface;
import org.osiris.persistence.controllers.TipoInterface;
import org.osiris.persistence.controllers.UsuarioInterface;
import org.osiris.persistence.controllers.exceptions.IllegalOrphanException;
import org.osiris.persistence.controllers.exceptions.PreexistingEntityException;
import org.osiris.server.utils.AppContext;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Repository;

@Repository
public class RequisitosManager {

	private ComplejidadInterface complejidadDAO;
	private DetalleInterface detalleDAO;
	private org.osiris.persistence.controllers.EstadoInterface estadoDAO;
	private IncertidumbreInterface incertidumbreDAO;
	private PrioridadInterface prioridadDAO;
	private ProyectoInterface proyectoDAO;	
	private RequisitoDeProyectoInterface reqProyectoDAO;	
	private RequisitoInterface requisitoDAO;
	private SucategoriaInterface subcategoriaDAO;	
	private UsuarioInterface usuarioDAO;
	private TipoInterface tipoDAO;

	Logger logger = Logger.getLogger(this.getClass());
	@Transient
	private ApplicationContext ctx = AppContext.getApplicationContext();
	public RequisitosManager(){
		super();
		if(complejidadDAO==null){
			complejidadDAO=(ComplejidadInterface) ctx.getBean("ComplejidadrequisitoJpaController");
		}
		if(estadoDAO==null){
			estadoDAO=(EstadoInterface) ctx.getBean("EstadorequisitoJpaController");
		}
		if(requisitoDAO==null){
			requisitoDAO=(RequisitoInterface) ctx.getBean("RequisitoJpaController");
		}

		if(usuarioDAO==null){
			usuarioDAO=(UsuarioInterface) ctx.getBean("UsuarioJpaController");
		}
		if(reqProyectoDAO==null){
			reqProyectoDAO=(RequisitoDeProyectoInterface) ctx.getBean("RequisitosdeproyectoJpaController");
		}
		if(subcategoriaDAO==null){
			subcategoriaDAO=(SucategoriaInterface) ctx.getBean("SubcategoriaJpaController");
		}
		if(incertidumbreDAO==null){
			incertidumbreDAO=(IncertidumbreInterface) ctx.getBean("IncertidumbreJpaController");
		}
		if(prioridadDAO==null){
			prioridadDAO=(PrioridadInterface) ctx.getBean("PrioridadrequisitoJpaController");
		}
		if(proyectoDAO==null){
			proyectoDAO=(ProyectoInterface) ctx.getBean("ProyectoJpaController");
		}
		if(detalleDAO==null){
			detalleDAO=(DetalleInterface) ctx.getBean("DetallerequisitoJpaController");
		}
		if(tipoDAO==null){
			tipoDAO=(TipoInterface) ctx.getBean("TiporequisitoJpaController");
		}
		
	}

	public Requisito getRequisito(Long req){
		return this.requisitoDAO.findRequisito(req);
	}
	public Riesgo asociarRiesgoARequisito(Long requisito,String descripcion,String nombre, Long usuario, String impacto, String probabilidad){
		Riesgo p = null;
		try{
			p=this.getRequisito(requisito).asociarNuevoRiesgoDependiente(descripcion, nombre, usuario, impacto, probabilidad);
		}catch(Exception me){
			me.printStackTrace();
		}
		return p;
	}
	public Boolean crearDependencia(long req1,long req2){
		try {
			this.getRequisito(req1).asignarNuevoRequisitoDependiente(this.getRequisito(req2), 1L);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return true;
	}
	public Boolean eliminarDependencia(long req1,long req2){
		try {
			this.getRequisito(req1).desasignarNuevoRequisitoDependiente(this.getRequisito(req2));
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return true;
	}
	public List<Riesgo> getRiesgosDeRequisito(long req){
		return this.requisitoDAO.findRequisito(req).getRiesgoList();
	}
	public List<Requisito> buscarRequisitos(String autor,
			String descripcion, 
			String detallerequisito, 
			Date fechaalta,
			Date fechabaja,
			Long idComplejidadRequisito,
			Long idEstadoRequisito, 
			Long idRequisito,
			Long idSubcategoria,
			Long idTipoRequisito, 
			String nombre,
			Integer PuntosFuncion, 
			String referencia, 
			String responsable,
			String origen,
			Long  proyecto,
			Long requisito_relacionado,
			boolean dependencia){
		
		logger.info("Buscando requisitos para:"+autor+","+ descripcion+","+ detallerequisito+","+ 
				fechaalta+","+ fechabaja+","+ idComplejidadRequisito+","+ idEstadoRequisito+","+ idRequisito+","+ idSubcategoria+","+ 
				idTipoRequisito+","+ nombre+","+ PuntosFuncion+","+ referencia+","+ responsable+","+ origen+","+proyecto);
		List<Requisito> result = this.requisitoDAO.buscarRequisitos(autor, descripcion, detallerequisito, 
				fechaalta, fechabaja, idComplejidadRequisito, idEstadoRequisito, idRequisito, idSubcategoria, 
				idTipoRequisito, nombre, PuntosFuncion, referencia, responsable, origen,proyecto,requisito_relacionado,dependencia);
		logger.info("Buscando requisitos para:"+autor+","+ descripcion+","+ detallerequisito+","+ 
				fechaalta+","+ fechabaja+","+ idComplejidadRequisito+","+ idEstadoRequisito+","+ idRequisito+","+ idSubcategoria+","+ 
				idTipoRequisito+","+ nombre+","+ PuntosFuncion+","+ referencia+","+ responsable+","+ origen+","+proyecto+" ENCONTRO "+result.size()+ " REQUISITOS");
		return result;

	}
	/**
	 * Unicamente se encargara de intermediar con JPA para el guardado del requisito (el mapeo con el bean se realizo anteriormente)
	 * 
	 * @param pRequisito
	 * @return
	 */
	public Requisito crearRequisito(
			String referencia,
			Long categoriaBiewBean,
			long estado,
			Integer pF,
			Long usuarioAlta,
			Long responsable,
			Long tipo,
			long subcategoria,
			long complejidad,
			String nombre,
			Integer version,
			String origen,
			String detalle,
			Long proyecto,
			Long prioridad,
			Long incertidumbre,
			String situacion,
			String resumen){
		logger.info("Guardando requisito en BD para:");
		logger.info("referencia:"+referencia);
		logger.info("categoriaBiewBean:"+categoriaBiewBean);
		logger.info("estado:"+estado);
		logger.info("pF:"+pF);
		logger.info("usuarioAlta:"+usuarioAlta);
		logger.info("responsable:"+responsable);
		logger.info("tipo:"+tipo);
		logger.info("subcategoria:"+subcategoria);
		logger.info("complejidad:"+complejidad);
		logger.info("nombre:"+nombre);
		logger.info("version:"+version);
		logger.info("origen:"+origen);
		logger.info("detalle:"+detalle);
		logger.info("proyecto:"+proyecto);
		logger.info("priorida:"+prioridad);
		logger.info("incertidumbre:"+incertidumbre);
		logger.info("situacion:"+situacion);

		Requisito pRequisito=new Requisito();
		pRequisito.setReferencia(referencia);
		pRequisito.setPuntosFuncion(pF);
		Usuario u = usuarioDAO.findUsuario(usuarioAlta);
		
		logger.info("Encontrado usuario:"+u);
		pRequisito.setDescripcion(resumen);
		pRequisito.setAutor(u);
		pRequisito.setResponsable(this.usuarioDAO.findUsuario(responsable));
		pRequisito.setIdComplejidadRequisito(this.complejidadDAO.findComplejidadrequisito(complejidad));
		pRequisito.setIdTipoRequisito(tipoDAO.findTiporequisito(tipo));
		pRequisito.setIdEstadoRequisito(this.estadoDAO.findEstadorequisito(estado));
		pRequisito.setIdSubcategoria(this.subcategoriaDAO.findSubcategoria(subcategoria));
		pRequisito.setFechaalta(new Date());
		pRequisito.setNombre(nombre);
		
		// a�adir observador
		pRequisito.anadirInteresado(u);
		logger.info("Guardo el requisito:"+pRequisito);
		pRequisito.crear();
		logger.info("Creado el requisito con id:"+pRequisito.getIdRequisito());
		if(proyecto!=null){
			logger.info("Se estaba asignado a un proyecto:"+proyecto);
			Requisitosdeproyecto reqpro=new Requisitosdeproyecto();
			reqpro.setEstadoRequistoEnProyecto(situacion);
			reqpro.setFechaalta(new Date());
			Incertidumbre in = incertidumbreDAO.findIncertidumbre(incertidumbre);
			logger.info("Encontrada incertidumbre:"+in);
			reqpro.setIdIncertidumbre(in);
			RequisitosdeproyectoPK requisitosdeproyectoPK=new RequisitosdeproyectoPK();
			requisitosdeproyectoPK.setIdProyecto(proyecto);
			requisitosdeproyectoPK.setIdRequisito(pRequisito.getIdRequisito());
			requisitosdeproyectoPK.setUsuarioalta(u.getIdUsuario());    
			reqpro.setRequisitosdeproyectoPK(requisitosdeproyectoPK);
			reqpro.setUsuario(u);
			reqpro.setRequisito(pRequisito);
			reqpro.setIdPrioridadRequisito(this.prioridadDAO.findPrioridadrequisito(prioridad));
			reqpro.setProyecto(this.proyectoDAO.findProyecto(proyecto));
			logger.info("Lo guardo asociandolo al proyecto:"+proyecto);
			try {
				this.reqProyectoDAO.create(reqpro);
			} catch (PreexistingEntityException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			logger.info("Lo anado a la lista de proyectos del requisito");
			pRequisito.getRequisitosdeproyectoList().add(reqpro);
		}
		logger.info("Creo el detalle");
		Detallerequisito detallerequisito=new Detallerequisito();
		detallerequisito.setDetalle(detalle);
		detallerequisito.setUsuarioalta(u);
		detallerequisito.setOrigen(origen);
		detallerequisito.setRequisito(pRequisito);    
		detallerequisito.setIdRequisito(pRequisito.getIdRequisito());
		try {
			this.detalleDAO.create(detallerequisito);
			logger.info("Se guarda detalle");
		} catch (IllegalOrphanException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (PreexistingEntityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		pRequisito.setDetallerequisito(detallerequisito);
		//pRequisito.modificar();
		logger.info("Actualizado requisito");
		return pRequisito;

	}

	public boolean desasociarRiesgoARequisito(Long requisito, Long riesgo) {
		logger.info("Desasociando requisito:"+requisito+" de riesgo:"+riesgo);
		try{
			this.getRequisito(requisito).desasociar(riesgo);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return true;
	}

}
